package com.recharge.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.recharge.common.domain.PageDO;
import com.recharge.common.enums.ErrorCode;
import com.recharge.common.result.ResultDO;
import com.recharge.common.result.ResultSupport;
import com.recharge.common.util.*;
import com.recharge.core.entity.GoodsEntity;
import com.recharge.core.entity.MerchantEntity;
import com.recharge.core.entity.ProviderEntity;
import com.recharge.core.entity.ProviderEntity;
import com.recharge.core.mapper.ProviderMapper;
import com.recharge.domain.query.ProviderQueryDO;
import com.recharge.domain.vo.MerchantDO;
import com.recharge.domain.vo.ProviderApiDO;
import com.recharge.domain.vo.ProviderDO;
import com.recharge.domain.vo.RouteFilterDO;
import com.recharge.service.GoodsProviderService;
import com.recharge.service.ProviderApiService;
import com.recharge.service.ProviderService;
import com.recharge.service.RouteFilterService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.stream.Collectors;

/**
 * <p>
 * 供应商 服务实现类
 * </p>
 *
 * @author reagan
 * @since 2020-08-19
 */
@Service
public class ProviderServiceImpl extends ServiceImpl<ProviderMapper, ProviderEntity> implements ProviderService {

    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private ProviderApiService providerApiService;
    @Autowired
    private RouteFilterService routeFilterService;
    @Autowired
    private GoodsProviderService goodsProviderService;

    @Transactional(propagation= Propagation.REQUIRED, rollbackFor= Exception.class)
    public ResultDO add(ProviderDO domain) {

        ProviderEntity entity = new ProviderEntity();

        ResultDO result = BeanUtilsExtends.copy(entity, domain);
        if (!result.isSuccess()) {
            logger.debug("error code：" + result.getErrorCode().getCode() + " msg" + result.getErrorCode().getMsg());
            return result;
        }

        Integer count = -1;
        try {
            count = baseMapper.selectCount(Wrappers.<ProviderEntity>lambdaQuery().eq(ProviderEntity::getProviderName, entity.getProviderName()).eq(ProviderEntity::getIsDelete, Constant.IS_DELETE_FALSE));
        } catch(Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }
        if(count != null && count >= 1){
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.PROVIDER_ADD_PROVIDER_NAME_EXIST_ERROR);
            logger.debug("error code：" + ErrorCode.PROVIDER_ADD_PROVIDER_NAME_EXIST_ERROR.getCode() + " msg" + ErrorCode.PROVIDER_ADD_PROVIDER_NAME_EXIST_ERROR.getMsg());
            return result;
        }

        entity.setCreateDate(Calendar.getInstance().getTime());
        entity.setModifiDate(entity.getCreateDate());
        entity.setModifier(entity.getCreator());
        entity.setProviderNo(SnowflakeIdWorker.getId());
        if(entity.getType() == Constant.PROVIDER_TYPE_2){
            entity.setPrivateKey(DESUtil.encrypt(entity.getPassword(), entity.getProviderNo() + "-" + entity.getPassword()));
        }

        boolean res = false;
        try {
            res = this.save(entity);
        } catch(Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }

        //判断r的值是否小于0.如果小于0 就代表添加失败
        if(!res) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.PROVIDER_ADD_ERROR);
            logger.debug("error code：" + ErrorCode.PROVIDER_ADD_ERROR.getCode() + " msg" + ErrorCode.PROVIDER_ADD_ERROR.getMsg());
            return result;
        }

        return result;
    }

    @Transactional(propagation= Propagation.REQUIRED, rollbackFor= Exception.class)
    public ResultDO edit(ProviderDO domain, String userName) {

        ProviderEntity entity = new ProviderEntity();

        ResultDO result = BeanUtilsExtends.copy(entity, domain);
        if (!result.isSuccess()) {
            logger.debug("error code：" + result.getErrorCode().getCode() + " msg" + result.getErrorCode().getMsg());
            return result;
        }

        entity.setModifiDate(Calendar.getInstance().getTime());

        Integer count = -1;
        try {
            count = baseMapper.selectCount(Wrappers.<ProviderEntity>lambdaQuery().eq(ProviderEntity::getProviderName, entity.getProviderName()).eq(ProviderEntity::getIsDelete, Constant.IS_DELETE_FALSE).ne(ProviderEntity::getId, entity.getId()));
        } catch(Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }
        if(count != null && count >= 1){
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.PROVIDER_ADD_PROVIDER_NAME_EXIST_ERROR);
            logger.debug("error code：" + ErrorCode.PROVIDER_ADD_PROVIDER_NAME_EXIST_ERROR.getCode() + " msg" + ErrorCode.PROVIDER_ADD_PROVIDER_NAME_EXIST_ERROR.getMsg());
            return result;
        }

        boolean res = false;
        try {
            res = this.updateById(entity);
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return result;
        }

        //判断r的值是否小于0.如果小于0 就代表添加失败
        if(!res) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.PROVIDER_EDIT_ERROR);
            logger.debug("error code：" + ErrorCode.PROVIDER_EDIT_ERROR.getCode() + " msg" + ErrorCode.PROVIDER_EDIT_ERROR.getMsg());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return result;
        }
        if(entity.getType() != Constant.PROVIDER_TYPE_2){
            int status = 1;
            redisUtil.set(Constant.PROVIDER_CARD + ":" + domain.getId(), domain.getCallback());
            if(entity.getStatus() == Constant.PROVIDER_STATUS_0){
                status = 2;
            } else if(entity.getStatus() == Constant.PROVIDER_STATUS_1){
                status = 1;
            }
            //修改供货商品关联
            result = goodsProviderService.updateStatus(entity.getId(), status, userName);
            if(!result.isSuccess()) {
                result.setSuccess(false);
                result.setErrorCode(ErrorCode.PROVIDER_EDIT_ERROR);
                logger.debug("error code：" + ErrorCode.PROVIDER_EDIT_ERROR.getCode() + " msg" + ErrorCode.PROVIDER_EDIT_ERROR.getMsg());
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return result;
            }
        }
        return result;
    }

    public ResultDO getByProviderNo(String providerNo) {

        ResultDO result = new ResultSupport();
        ProviderEntity entity = null;

        try {
            entity = this.getBaseMapper().selectOne(Wrappers.<ProviderEntity>lambdaQuery().eq(ProviderEntity::getProviderNo, providerNo));
        } catch(Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }

        ProviderDO domain = getDomain(entity);

        result.setModel(ResultDO.FIRST_MODEL_KEY, domain);

        return result;
    }

    
    public ResultDO get(String id) {

        ResultDO result = new ResultSupport();
        ProviderEntity entity = null;

        try {
            entity = this.getById(id);
        } catch(Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }

        ProviderDO domain = getDomain(entity);

        result.setModel(ResultDO.FIRST_MODEL_KEY, domain);

        return result;
    }

    @Transactional(propagation= Propagation.REQUIRED, rollbackFor= Exception.class)
    public ResultDO remove(String id, String modifier) {

        //删除供货API
        ResultDO result = providerApiService.removeByProviderId(id, modifier);
        if(!result.isSuccess()) {
            logger.debug("error code：" + result.getErrorCode().getCode() + " msg" + result.getErrorCode().getMsg());
            if(ErrorCode.SYSTEM_EXCEPTION.getCode() == result.getErrorCode().getCode()){
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return result;
            }
        }
        //删除供货关联
        result = goodsProviderService.removeByProviderId(id, modifier);
        if(!result.isSuccess()) {
            logger.debug("error code：" + result.getErrorCode().getCode() + " msg" + result.getErrorCode().getMsg());
            if(ErrorCode.SYSTEM_EXCEPTION.getCode() == result.getErrorCode().getCode()){
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return result;
            }
        }

        ProviderEntity entity = new ProviderEntity();

        entity.setModifiDate(Calendar.getInstance().getTime());
        entity.setModifier(modifier);
        entity.setId(id);
        entity.setIsDelete(Constant.IS_DELETE);

        boolean res = false;
        try {
            res = this.updateById(entity);
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return result;
        }

//        //判断r的值是否小于0.如果小于0 就代表添加失败
//        if(!res) {
//            result.setSuccess(false);
//            result.setErrorCode(ErrorCode.DELETE_PROVIDER_ERROR);
//            logger.debug("error code：" + ErrorCode.DELETE_PROVIDER_ERROR.getCode() + " msg" + ErrorCode.DELETE_PROVIDER_ERROR.getMsg());
//            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
//            return result;
//        }

        return result;
    }

    public ResultDO listAll() {

        ProviderEntity entity = new ProviderEntity();

        ResultDO result = new ResultSupport();

        if (!result.isSuccess()) {
            logger.debug("error code：" + result.getErrorCode().getCode() + " msg" + result.getErrorCode().getMsg());
            return result;
        }

        QueryWrapper<ProviderEntity> wrapper = new QueryWrapper<>(entity);
        wrapper.eq("is_delete", 1);
        List<ProviderEntity> list = null;
        try {
            list = baseMapper.selectList(wrapper);
        }catch (Exception e){
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }

        List<ProviderDO> doList = getDomainList(list);

        result.setModel(ResultDO.FIRST_MODEL_KEY, doList);
        return result;
    }

    public ResultDO listCardProviderAll() {

        ProviderEntity entity = new ProviderEntity();

        ResultDO result = new ResultSupport();

        if (!result.isSuccess()) {
            logger.debug("error code：" + result.getErrorCode().getCode() + " msg" + result.getErrorCode().getMsg());
            return result;
        }

        QueryWrapper<ProviderEntity> wrapper = new QueryWrapper<>(entity);
        wrapper.eq("type", Constant.PROVIDER_TYPE_2);
        wrapper.eq("is_delete", Constant.IS_DELETE_FALSE);
        List<ProviderEntity> list = null;
        try {
            list = baseMapper.selectList(wrapper);
        }catch (Exception e){
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }

        List<ProviderDO> doList = getDomainList(list);

        result.setModel(ResultDO.FIRST_MODEL_KEY, doList);
        return result;
    }

    public void initThreshold() {
        ResultDO result = listAll();
        List<ProviderDO> list = (List<ProviderDO>) result.getModel(ResultDO.FIRST_MODEL_KEY);
        for(ProviderDO domain : list) {
            redisUtil.set(Constant.PROVIDER_CURRENT_SEND_COUNT + ":" + domain.getId(), 0);
            redisUtil.set(Constant.PROVIDER_LAST_TIME + ":" + domain.getId(), 0);
        }
    }

    @Override
    public ResultDO getListByMerchantId(String merchantId) {
        ResultDO result = new ResultSupport();
        if(StringUtils.isEmpty(merchantId)){
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.PARAM_GET_ERROR);
            logger.debug("error code：" + ErrorCode.PARAM_GET_ERROR.getCode() + " msg" + ErrorCode.PARAM_GET_ERROR.getMsg());
            return result;
        }
        List<ProviderEntity> mList = baseMapper.selectList(Wrappers.<ProviderEntity>lambdaQuery().eq(ProviderEntity::getIsDelete, Constant.IS_DELETE_FALSE).eq(ProviderEntity::getStatus, Constant.MERCHANT_STATUS_1));
        if(mList == null || mList.isEmpty()){
            return result;
        }
        List<ProviderDO> doList = mList.stream().map( item -> getDomain(item)).collect(Collectors.toList());
        //根据供应商ID查询路由  白名单排除
        result =  routeFilterService.findRouterByMerchantId(merchantId,Constant.ROUTER_FILTER_TYPE_2);
        if(!result.isSuccess()){
            logger.debug("error code：" + result.getErrorCode().getCode() + " msg" + result.getErrorCode().getMsg());
            return result;
        }
        RouteFilterDO routeFilterDO = (RouteFilterDO) result.getModel(ResultDO.FIRST_MODEL_KEY);
        if(routeFilterDO != null){
            List<String> whiteList = routeFilterDO.getProviderIds();
            if(whiteList != null && !whiteList.isEmpty()){
                doList = doList.stream().filter(item -> !whiteList.contains(item.getId())).collect(Collectors.toList());
            }
        }
        //根据供应商ID查询路由  黑名单排除
        result = routeFilterService.findRouterByMerchantId(merchantId,Constant.ROUTER_FILTER_TYPE_1);
        if(!result.isSuccess()){
            logger.debug("error code：" + result.getErrorCode().getCode() + " msg" + result.getErrorCode().getMsg());
            return result;
        }
        routeFilterDO = (RouteFilterDO) result.getModel(ResultDO.FIRST_MODEL_KEY);

        if(routeFilterDO != null){
            List<String> blackList = routeFilterDO.getProviderIds();
            if(blackList != null && !blackList.isEmpty()){
                doList = doList.stream().filter(item -> !blackList.contains(item.getId())).collect(Collectors.toList());
            }
        }
        result.setModel(ResultDO.FIRST_MODEL_KEY, doList);
        return result;
    }


    public ResultDO find(ProviderQueryDO domain) {
        ProviderEntity entity = new ProviderEntity();
        ResultDO result = new ResultSupport();
        if (!result.isSuccess()) {
            logger.debug("error code：" + result.getErrorCode().getCode() + " msg" + result.getErrorCode().getMsg());
            return result;
        }
        QueryWrapper<ProviderEntity> wrapper = new QueryWrapper<>(entity);
        wrapper.lambda().eq(ProviderEntity::getIsDelete, Constant.IS_DELETE_FALSE);

        if (StringUtils.isNotEmpty(domain.getProviderName())){
            wrapper.lambda().like(ProviderEntity::getProviderName,domain.getProviderName());
        }

        if (StringUtils.isNotEmpty(domain.getProviderNo())){
            wrapper.lambda().like(ProviderEntity::getProviderNo,domain.getProviderNo());
        }

        if (StringUtils.isNotEmpty(domain.getTelephone())){
            wrapper.lambda().like(ProviderEntity::getTelephone,domain.getTelephone());
        }

        if (StringUtils.isNotEmpty(domain.getContact())){
            wrapper.lambda().like(ProviderEntity::getContact,domain.getContact());
        }

        if(domain.getType() != null && domain.getType().length >0){
            wrapper.lambda().and( newWrapper -> {
                newWrapper.and( groupIdWrapper -> {
                    for (Integer type : domain.getType()) {
                        groupIdWrapper.or(itemWrapper -> itemWrapper.eq(ProviderEntity::getType, type));
                    }
                });
            });
        }
        wrapper.lambda().orderByDesc(ProviderEntity::getCreateDate);
        Page<ProviderEntity> page = new Page<>(domain.getCurrentPage(),domain.getPageSize());
        IPage iPage = null;

        try {
            iPage = baseMapper.selectPage(page,wrapper);
        }catch (Exception e){
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.SYSTEM_EXCEPTION);
            logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
            return result;
        }

        List<ProviderDO> doList = getDomainList(iPage.getRecords());

        //查询余额
        if(doList != null && doList.size() >0 && domain.isQueryBalance()){
            doList.stream().forEach( item -> {
                try {
                    ResultDO resultDomain = providerApiService.getByProviderNo(item.getProviderNo());
                    if(resultDomain.isSuccess()){
                        ProviderApiDO providerApiDO = (ProviderApiDO) resultDomain.getModel(ResultDO.FIRST_MODEL_KEY);
                        resultDomain = providerApiService.queryBalance(providerApiDO);
                        if(resultDomain.isSuccess()){
                            String balance = (String) resultDomain.getModel(ResultDO.FIRST_MODEL_KEY);
                            item.setBalance(StringUtils.isEmpty(balance) ? "null" : balance);
                        } else {
                            item.setBalance((String) resultDomain.getModel(ResultDO.FIRST_MODEL_KEY));
                        }
                    } else {
                        item.setBalance("未配置接口API");
                    }
                }catch (Exception e){
                    logger.debug("error code：" + ErrorCode.SYSTEM_EXCEPTION.getCode() + " msg" + ErrorCode.SYSTEM_EXCEPTION.getMsg());
                    item.setBalance("查询失败，系统异常");
                }
            });
        }

        PageDO<ProviderDO> pageDO = new PageDO<>();

        pageDO.setCurrentPage(iPage.getCurrent());
        pageDO.setPageCount(iPage.getPages());
        pageDO.setPageSize(iPage.getSize());
        pageDO.setRowCount(iPage.getTotal());
        pageDO.setData(doList);

        result.setModel(ResultDO.FIRST_MODEL_KEY, pageDO);
        return result;
    }

    @Transactional(propagation= Propagation.REQUIRED, rollbackFor= Exception.class)
    @Override
    public ResultDO resetSecretKey(String id, String username) {

        ResultDO result = new ResultSupport();

        ProviderEntity providerEntity =  this.getById(id);

        ProviderEntity entity = new ProviderEntity();

        entity.setModifiDate(Calendar.getInstance().getTime());
        entity.setModifier(username);
        String password = SnowflakeIdWorker.getId();
        entity.setPrivateKey(DESUtil.encrypt(password, providerEntity.getProviderNo() + "-" + password));
        entity.setPassword(password);
        entity.setId(id);

        boolean res = false;
        try {
            res = this.updateById(entity);
        } catch (Exception e) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.API_MERCHANT_KEY_RESET);
            logger.debug("error code：" + ErrorCode.API_MERCHANT_KEY_RESET.getCode() + " msg" + ErrorCode.API_MERCHANT_KEY_RESET.getMsg());
            return result;
        }

        //判断r的值是否小于0.如果小于0 就代表添加失败
        if(!res) {
            result.setSuccess(false);
            result.setErrorCode(ErrorCode.API_MERCHANT_KEY_RESET);
            logger.debug("error code：" + ErrorCode.API_MERCHANT_KEY_RESET.getCode() + " msg" + ErrorCode.API_MERCHANT_KEY_RESET.getMsg());
            return result;
        }

        return result;
    }

    private ProviderDO getDomain(ProviderEntity entity) {

        //判断房源对象是否为空，为空就返回 空，不为空就进行下面的代码
        if(entity == null) return null;
        ProviderDO domain = new ProviderDO();

        domain = BeanUtilsExtends.copyProperties(domain, entity) ? domain : null;

        //判断拷贝数据到Dto对象是否成功，如果成功则返回domian，如果不成功就返回空
        return domain;
    }

    private List<ProviderDO> getDomainList(List<ProviderEntity> list) {
        //创建一个名为dolist的房源do类型的 list集合
        List<ProviderDO> doList = new ArrayList<ProviderDO>();

        //判断传入的list的集合的size是否大于0
        if(list.size() > 0) {
            //大于0是，遍历list，创建do类型的对象 调用getdomain方法
            for(ProviderEntity entity : list) {

                ProviderDO domain = this.getDomain(entity);

                //判断得到的domain 是否为空 不为空 就往dolist集合里面添加domian 为空就返回空
                if(domain == null) {
                    return null;
                }
                doList.add(domain);
            }
        } else {
            return null;
        }
        return doList;
    }
}
